from PyQt4 import QtCore, QtGui;

class private_data:
	def __init__(self, parent):
		self.headerModel = None;
		self.mouseHover = None;
		self.mouseClick = None;
		self.rectClick = None;
		self.hParent = parent;
		
	def initFromNewModel(self, orientation, model):		
		if orientation == QtCore.Qt.Horizontal:
			orientationRole = HierarchicalHeaderView.HorizontalHeaderDataRole;
		else:
			orientationRole = HierarchicalHeaderView.VerticalHeaderDataRole;
		self.headerModel = model.data(QtCore.QModelIndex(), orientationRole);
		
#	def findRootIndex(self,index):
#		while index.parent().isValid() :
#			index=index.parent()
#		return index;

	def parentIndexes(self, index):
		indexes = []
		while index.isValid():
			indexes.insert(0, index)
			index = index.parent()
		return indexes;

	def findLeaf(self, currentIndex, sectionIndex, currentLeafIndex):
		if currentIndex.isValid():
			childCount = currentIndex.model().columnCount(currentIndex)
			if childCount:
				for i in range(childCount):
					MI, currentLeafIndex = self.findLeaf(currentIndex.child(0, i), 
														sectionIndex, currentLeafIndex)
					res = QtCore.QModelIndex(MI)
					if res.isValid():
						return res, currentLeafIndex
			else:
				currentLeafIndex += 1
				if currentLeafIndex == sectionIndex:
					return currentIndex, currentLeafIndex
		return QtCore.QModelIndex(), currentLeafIndex

	def leafIndex(self, sectionIndex):
		if self.headerModel:
			currentLeafIndex = -1
			for i in range(self.headerModel.columnCount()):
				MI, currentLeafIndex = self.findLeaf(self.headerModel.index(0, i), 
												sectionIndex, currentLeafIndex)
				res = QtCore.QModelIndex(MI)
				if res.isValid():
					return res
		return QtCore.QModelIndex();

	def searchLeafs(self, currentIndex):
		res = []
		if(currentIndex.isValid()):
			childCount = currentIndex.model().columnCount(currentIndex)
			if childCount:
				for i in range(childCount):
						res += self.searchLeafs(currentIndex.child(0, i))
			else:
				res.append(currentIndex)
		return res

	def leafs(self, searchedIndex):
		leafs = []
		if searchedIndex.isValid():
			childCount = searchedIndex.model().columnCount(searchedIndex)
			for i in range(childCount):
				leafs += self.searchLeafs(searchedIndex.child(0, i))
		return leafs;

	def setForegroundBrush(self, opt, index):
		foregroundBrush = index.data(QtCore.Qt.ForegroundRole)
		if issubclass(foregroundBrush.__class__, QtGui.QBrush):
			opt.palette.setBrush(QtGui.QPalette.ButtonText, foregroundBrush)

	def setBackgroundBrush(self, opt, index):
		backgroundBrush = index.data(QtCore.Qt.BackgroundRole);
		if issubclass(backgroundBrush.__class__, QtGui.QBrush):
			opt.palette.setBrush(QtGui.QPalette.Button, backgroundBrush);
			opt.palette.setBrush(QtGui.QPalette.Window, backgroundBrush);

	def cellSize(self, leafIndex, hv, styleOptions):
		res = QtCore.QSize()
		vS = leafIndex.data(QtCore.Qt.SizeHintRole)
		if vS and issubclass(vS.__class__, QtCore.QSize):
			res = vS
		fnt = QtGui.QFont(hv.font());
		vF = leafIndex.data(QtCore.Qt.FontRole)
		if vF and issubclass(vF.__class__, QtGui.QFont):
			fnt = vF
		fnt.setBold(True);
		fm = QtGui.QFontMetrics(fnt)
		size = QtCore.QSize(fm.size(0, str(leafIndex.data(QtCore.Qt.DisplayRole))))
		if leafIndex.data(QtCore.Qt.UserRole) != None:
			size.transpose()
		decorationsSize = QtCore.QSize(hv.style().sizeFromContents(QtGui.QStyle.CT_HeaderSection, styleOptions, QtCore.QSize(), hv))
		emptyTextSize = QtCore.QSize(fm.size(0, ""));
		return res.expandedTo(size + decorationsSize - emptyTextSize);

	def currentCellWidth(self, searchedIndex, leafIndex, sectionIndex, hv):
		leafsList = self.leafs(searchedIndex)
		if len(leafsList) == 0:
			return hv.sectionSize(sectionIndex);
		width = 0
		firstLeafSectionIndex = sectionIndex - leafsList.index(leafIndex)
		for i in range(len(leafsList)):
			width += hv.sectionSize(firstLeafSectionIndex + i);
		return width

	def currentCellLeft(self, searchedIndex, leafIndex, sectionIndex, left, hv):
		leafsList = self.leafs(searchedIndex)
		if len(leafsList) > 0:
			n = leafsList.index(leafIndex)
			firstLeafSectionIndex = sectionIndex - n;
			n -= 1;
			while n >= 0:
				left -= hv.sectionSize(firstLeafSectionIndex + n)
				n -= 1
		return left

	def paintHorizontalCell(self, painter, hv, cellIndex, leafIndex, logicalLeafIndex, styleOptions, sectionRect, top):
		uniopt = QtGui.QStyleOptionHeader(styleOptions)
		self.setForegroundBrush(uniopt, cellIndex)
		self.setBackgroundBrush(uniopt, cellIndex)
		height = self.cellSize(cellIndex, hv, uniopt).height()
		if cellIndex == leafIndex:
			height = sectionRect.height() - top;		
		left = self.currentCellLeft(cellIndex, leafIndex, logicalLeafIndex, sectionRect.left(), hv);
		width = self.currentCellWidth(cellIndex, leafIndex, logicalLeafIndex, hv);

		r = QtCore.QRect(left, top, width, height);
		uniopt.text = cellIndex.data(QtCore.Qt.DisplayRole).toString();
		painter.save()
		uniopt.rect = r;
		if cellIndex.data(QtCore.Qt.UserRole) != None: #If is Rotated 90 degreees
			hv.style().drawControl(QtGui.QStyle.CE_HeaderSection, uniopt, painter, hv)
			m = QtGui.QMatrix()
			m.rotate(-90)
			painter.setWorldMatrix(m, True)
			new_r = QtCore.QRect(0, 0, r.height(), r.width())
			new_r.moveCenter(QtCore.QPoint(-r.center().y(), r.center().x()));
			uniopt.rect = new_r;
			hv.style().drawControl(QtGui.QStyle.CE_HeaderLabel, uniopt, painter, hv);
		else:
			hv.style().drawControl(QtGui.QStyle.CE_Header, uniopt, painter, hv);
		painter.restore()
		return top + height; #, left + width, r;
	
	def getCellInfo(self, hv, cellIndex, leafIndex, logicalLeafIndex, styleOptions, sectionRect, top):
		uniopt = QtGui.QStyleOptionHeader(styleOptions);
		self.setForegroundBrush(uniopt, cellIndex);
		self.setBackgroundBrush(uniopt, cellIndex);
		height = self.cellSize(cellIndex, hv, uniopt).height();
		if cellIndex == leafIndex:
			height = sectionRect.height() - top;
		left = self.currentCellLeft(cellIndex, leafIndex, logicalLeafIndex, sectionRect.left(), hv);
		width = self.currentCellWidth(cellIndex, leafIndex, logicalLeafIndex, hv);
		qRect = QtCore.QRect(left, top, width, height);
		sLabel = cellIndex.data(QtCore.Qt.DisplayRole).toString();
		return qRect, sLabel;

	def paintHorizontalSection(self, painter, sectionRect, logicalLeafIndex, hv, styleOptions, leafIndex):
		oldBO = QtCore.QPointF(painter.brushOrigin())
		top = sectionRect.y();
		indexes = self.parentIndexes(leafIndex)
#		print len(indexes), len(indexes)-2;
#		print top;
		for i in range(len(indexes)):
			realStyleOptions = QtGui.QStyleOptionHeader(styleOptions)
#			if i<len(indexes)-1:
#				t = QtGui.QStyle.State(QtGui.QStyle.State_Sunken | QtGui.QStyle.State_On);
#				realStyleOptions.state&=(~t);
#			realStyleOptions.state=QtGui.QStyle.State(QtGui.QStyle.State_MouseOver);
			qR, sLbl = self.getCellInfo(hv, indexes[i], leafIndex, logicalLeafIndex, realStyleOptions, sectionRect, top); #@UnusedVariable
#				print sLbl;

			
#			if self.mouseClick!=None:
#				t = QtGui.QStyle.State(QtGui.QStyle.State_Sunken | QtGui.QStyle.State_On);
#				realStyleOptions.state&=(~t);
#				if qR.contains(self.mouseClick):
#					self.rectClick = qR;
#					realStyleOptions.state=QtGui.QStyle.State(QtGui.QStyle.State_Sunken | QtGui.QStyle.State_On);
#				elif self.rectClick!=None:
#					clickL, clickR = self.rectClick.x(), self.rectClick.x()+self.rectClick.width();
#					clickB = self.rectClick.y()+self.rectClick.height();
#					if qR.x() >= clickL and qR.x() <= clickR and qR.y() >= clickB:
#						realStyleOptions.state=QtGui.QStyle.State(QtGui.QStyle.State_Sunken | QtGui.QStyle.State_On);
			

			if self.mouseClick!=None and self.hParent.cursor().shape()!=QtCore.Qt.SplitHCursor:
				pX = self.mouseClick.x();
				pL, pR = qR.x(), qR.x()+qR.width();
				if pX > pL and pX < pR:
					realStyleOptions.state=QtGui.QStyle.State(QtGui.QStyle.State_Sunken | QtGui.QStyle.State_On);
			if self.hParent.selectedColumns.count(logicalLeafIndex)==0 and \
			realStyleOptions.state!=QtGui.QStyle.State(QtGui.QStyle.State_Sunken | QtGui.QStyle.State_On) and\
			self.mouseHover!=None and qR.contains(self.mouseHover):
				realStyleOptions.state=QtGui.QStyle.State(QtGui.QStyle.State_MouseOver);

#			print "LevelRow=", i, ",", "Column=", logicalLeafIndex, ",", sLbl, ",", qR;
			top = self.paintHorizontalCell(painter, hv, indexes[i], leafIndex, logicalLeafIndex, realStyleOptions, sectionRect, top);
#			print r, "[LevelRow=", i, ", PosY1=", top-23, ", PosY2=", top, "]", "[Column=", \
#			logicalLeafIndex, ", PosX1=", sectionRect.x(), ", PosX2=", left, "]";
		painter.setBrushOrigin(oldBO);
		
	def paintVerticalCell(self, painter, hv, cellIndex, leafIndex, logicalLeafIndex, styleOptions, sectionRect, left):
						uniopt = QtGui.QStyleOptionHeader(styleOptions)
						self.setForegroundBrush(uniopt, cellIndex)
						self.setBackgroundBrush(uniopt, cellIndex)
						width = self.cellSize(cellIndex, hv, uniopt).width()
						if cellIndex == leafIndex:
								width = sectionRect.width() - left
						top = self.currentCellLeft(cellIndex, leafIndex, logicalLeafIndex, sectionRect.top(), hv)
						height = self.currentCellWidth(cellIndex, leafIndex, logicalLeafIndex, hv)
						r = QtCore.QRect(left, top, width, height)
						uniopt.text = cellIndex.data(QtCore.Qt.DisplayRole).toString();
						painter.save()
						uniopt.rect = r;
						if cellIndex.data(QtCore.Qt.UserRole) != None:
								hv.style().drawControl(QtGui.QStyle.CE_HeaderSection, uniopt, painter, hv)
								m = QtGui.QMatrix()
								m.rotate(-90)
								painter.setWorldMatrix(m, True);
								new_r = QtCore.QRect(0, 0, r.height(), r.width())
								new_r.moveCenter(QtCore.QPoint(-r.center().y(), r.center().x()))
								uniopt.rect = new_r
								hv.style().drawControl(QtGui.QStyle.CE_HeaderLabel, uniopt, painter, hv)
						else:
								hv.style().drawControl(QtGui.QStyle.CE_Header, uniopt, painter, hv)
						painter.restore()
						return left + width

	def paintVerticalSection(self, painter, sectionRect, logicalLeafIndex, hv, styleOptions, leafIndex):
						oldBO = QtCore.QPointF(painter.brushOrigin())
						left = sectionRect.x();
						indexes = self.parentIndexes(leafIndex)
						for i in range(len(indexes)):
								realStyleOptions = QtGui.QStyleOptionHeader(styleOptions)
								#if(	 i<indexes.size()-1
								#		&&
								#			(	 realStyleOptions.state.testFlag(QStyle::State_Sunken)
								#			 || realStyleOptions.state.testFlag(QStyle::State_On)))
								#{
								#		QStyle::State t(QStyle::State_Sunken | QStyle::State_On);
								#		realStyleOptions.state&=(~t);
								#}
								left = self.paintVerticalCell(painter, hv, indexes[i], leafIndex, logicalLeafIndex, realStyleOptions, sectionRect, left)
						painter.setBrushOrigin(oldBO);


class HierarchicalHeaderView(QtGui.QHeaderView):
	HorizontalHeaderDataRole = QtCore.Qt.UserRole
	VerticalHeaderDataRole = QtCore.Qt.UserRole + 1

	def __init__(self, orientation, parent=None):
		QtGui.QHeaderView.__init__(self, orientation, parent)
		self._pd = private_data(self);
		self.connect(self, QtCore.SIGNAL("sectionResized(int, int, int)"), self.on_sectionResized);
		self.tParent = parent;
		self.selectedColumns = [];
		self.bMouseHover = False;
	
	def styleOptionForCell(self, logicalInd):
		opt = QtGui.QStyleOptionHeader()
		self.initStyleOption(opt);
		if (self.window().isActiveWindow()):
			opt.state |= QtGui.QStyle.State_Active;
		opt.textAlignment = QtCore.Qt.AlignCenter;
		opt.iconAlignment = QtCore.Qt.AlignVCenter;
		opt.section = logicalInd
		visual = self.visualIndex(logicalInd);
		if self.count() == 1:
			opt.position = QtGui.QStyleOptionHeader.OnlyOneSection;
		else:
			if (visual == 0):
				opt.position = QtGui.QStyleOptionHeader.Beginning;
			else:
				opt.position = (QtGui.QStyleOptionHeader.End if visual == self.count() - 1 else QtGui.QStyleOptionHeader.Middle);
		if self.isClickable():
			if self.orientation() == QtCore.Qt.Horizontal:
				bSelectColumn, bSelectCell = False, False;
				for sRange in self.tParent.selectedRanges():				
					if sRange.rightColumn()>=logicalInd and sRange.leftColumn()<=logicalInd:
						bSelectCell = True;
				for i in range(len(self.selectedColumns)):
					if self.selectedColumns[i] == logicalInd:
						bSelectColumn = True;
				if bSelectCell:
					opt.state |= QtGui.QStyle.State_On;
				if bSelectColumn:
					opt.state |= QtGui.QStyle.State_Sunken;
		return opt;
	
	#protected??
	def paintSection(self, painter, rect, logicalIndex):
		if rect.isValid():
			leafIndex = QtCore.QModelIndex(self._pd.leafIndex(logicalIndex));
			if leafIndex.isValid():
				if(self.orientation() == QtCore.Qt.Horizontal):
					self._pd.paintHorizontalSection(painter, rect, logicalIndex, self, self.styleOptionForCell(logicalIndex), leafIndex);
				else:
					self._pd.paintVerticalSection(painter, rect, logicalIndex, self, self.styleOptionForCell(logicalIndex), leafIndex);
				return
		QtGui.QHeaderView.paintSection(self, painter, rect, logicalIndex);
	
	#Resize the Headers to Fit the Content (Only increases size to fit extra headers)
	def sectionSizeFromContents(self, logicalIndex):
		curLeafIndex = QtCore.QModelIndex(self._pd.leafIndex(logicalIndex));
#		print curLeafIndex.data(0).toString();
		if curLeafIndex.isValid():
			styleOption = QtGui.QStyleOptionHeader(self.styleOptionForCell(logicalIndex));
			s = QtCore.QSize(self._pd.cellSize(curLeafIndex, self, styleOption));
			f = QtGui.QFontMetrics(QtGui.QFont());
			fontSize = f.size(QtCore.Qt.TextDontClip, curLeafIndex.data(0).toString());
			s.setHeight(fontSize.height()+10);
			s.setWidth(fontSize.width()+14);
			curLeafIndex = curLeafIndex.parent();
			while curLeafIndex.isValid():
				if self.orientation() == QtCore.Qt.Horizontal:
					s.setHeight(s.height() + self._pd.cellSize(curLeafIndex, self, styleOption).height());
#					s.setWidth(0);
				else:
					s.setWidth(s.width() + self._pd.cellSize(curLeafIndex, self, styleOption).width());
				curLeafIndex = curLeafIndex.parent();
			return s;
		return QtGui.QHeaderView.sectionSizeFromContents(self, logicalIndex);

	def setModel(self, model):
		self._pd.initFromNewModel(self.orientation(), model);
		QtGui.QHeaderView.setModel(self, model)
		cnt = (model.columnCount() if self.orientation() == QtCore.Qt.Horizontal else model.rowCount())
		if cnt: self.initializeSections(0, cnt - 1);	
		
	def mouseMoveEvent(self, event):
		super(HierarchicalHeaderView, self).mouseMoveEvent(event);
#		print event.pos();
#		self.emit(QtCore.SIGNAL("sectionResized()"), 0,0,0);
		if self.bMouseHover:
			self._pd.mouseHover = event.pos();
		else:
			self._pd.mouseHover = None;
		self.reset();
#		print self.cursor().shape()==QtCore.Qt.SplitHCursor;
#		print self.cursor().shape();
		
	def leaveEvent(self, event):
		super(HierarchicalHeaderView, self).leaveEvent(event);
		self._pd.mouseHover = None;
		self.bMouseHover = False;
		self.reset();
#		self._pd.mouseHover = None;
#		self.reset();
		
	def enterEvent(self, event):
		super(HierarchicalHeaderView, self).enterEvent(event);
		self.bMouseHover = True;
		self.reset();
		
	def mousePressEvent(self, event):
		super(HierarchicalHeaderView, self).mousePressEvent(event);
		if self.cursor().shape()!=QtCore.Qt.SplitHCursor:
			self._pd.mouseClick = event.pos();
		self.reset();
#		print event.pos(), self.tParent.columnCount(), self.tParent.rowCount();

	def mouseReleaseEvent(self, event):
		super(HierarchicalHeaderView, self).mouseReleaseEvent(event);
		self.reset();
		
	def onTableItemSelectionChanged(self):
		selectedColumns = [];
		for i in range(self.tParent.columnCount()):
			mSelect = self.tParent.selectionModel();
			if mSelect.isColumnSelected(i, self.tParent.rootIndex()):
				selectedColumns.append(i);
		self.selectedColumns = selectedColumns;
		self._pd.mouseClick = None;
		self.reset();
	
	#Slot [Refresh the drawing of Header labels when resized]
	def on_sectionResized(self, logicalIndex):
#		if self.isSectionHidden(logicalIndex): return;
#		leafIndex = QtCore.QModelIndex(self._pd.leafIndex(logicalIndex));
#		if leafIndex.isValid():
#			leafsList = self._pd.leafs(self._pd.findRootIndex(leafIndex));
#			for n in range(leafsList.index(leafIndex),1,-1): #(int n=leafsList.indexOf(leafIndex); n>0; --n) @UnusedVariable
#				logicalIndex-=1;
#				w = self.viewport().width()
#				h = self.viewport().height()
#				pos = self.sectionViewportPosition(logicalIndex)
#				r=QtCore.QRect(pos, 0, w - pos, h)
#				if self.orientation() == QtCore.Qt.Horizontal:
#					if self.isRightToLeft(): r.setRect(0, 0, pos + self.sectionSize(logicalIndex), h);
#				else:
#					r.setRect(0, pos, w, h - pos);
#				self.viewport().update(r.normalized());
		w = self.viewport().width();
		h = self.viewport().height();
		r = QtCore.QRect(0, 0, w, h);
		self.viewport().update(r.normalized());
		
		
##		print "Resizing: logicalIndex = ", logicalIndex;
#		if self.isSectionHidden(logicalIndex): return;
#		leafIndex = QtCore.QModelIndex(self._pd.leafIndex(logicalIndex));
##		print leafIndex.row(), leafIndex.column();
#		if leafIndex.isValid():
#			leafsList = self._pd.leafs(self._pd.findRootIndex(leafIndex));
##			print leafsList[0].row(), leafsList[0].column(), "::", leafsList[1].row(), leafsList[1].column();
#			try:
##				print "leafsList.index(leafIndex)=", leafsList.index(leafIndex);
#				for n in range(leafsList.index(leafIndex), -1, -1): #(int n=leafsList.indexOf(leafIndex); n>0; --n) @UnusedVariable
##					print "n=",n;
##					logicalIndex -= 1;
#					w = self.viewport().width();
#					h = self.viewport().height();
#					pos = self.sectionViewportPosition(logicalIndex);
##					print pos;
#					r = QtCore.QRect(pos, 0, w - pos, h);
##					print r;
#					if self.orientation() == QtCore.Qt.Horizontal:
#						if self.isRightToLeft(): 
#							r.setRect(0, 0, pos + self.sectionSize(logicalIndex), h);
#					else:
#						r.setRect(0, pos, w, h - pos);
#					self.viewport().update(r.normalized());
#			except:
#				print "Nothing found";
#				return;